package com.juejin.www.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.juejin.www.dao.*;
import com.juejin.www.model.DO.Article;
import com.juejin.www.model.DO.Audit;
import com.juejin.www.model.DTO.ArticleDTO;
import com.juejin.www.model.DTO.PageDTO;
import com.juejin.www.model.DTO.UserDTO;
import com.juejin.www.model.VO.ArticleVO;
import com.juejin.www.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import static com.juejin.www.constant.Constant.HIT_ARTICLE_VIEW_COUNT;

/**
 * @author Jacky
 */
@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleDao articleDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private AdminDao adminDao;

    @Autowired
    private LikeDao likeDao;

    @Autowired
    private CommentDao commentDao;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public PageDTO<ArticleVO> list(Integer currentPage,Integer pageSize) {
        Integer begin = (currentPage - 1) * pageSize;
        List<Article> articles = articleDao.list(begin,pageSize);
        List<ArticleVO> articleVos = articles.stream()
                .map(article -> {
                    UserDTO author = userDao.getById(article.getAuthorId());
                    return new ArticleVO(
                            article.getId(),
                            article.getTitle(),
                            article.getContent().substring(0, Math.min(article.getContent().length(), 40)) + "...",
                            author.getName(),
                            article.getAuthorId(),
                            article.getCreateTime(),
                            article.getViewCount(),
                            article.getLikeCount(),
                            article.getCommentCount(),
                            null
                    );
                })
                .collect(Collectors.toList());
        Integer totalCount = articleDao.getTotalCount();
        PageDTO<ArticleVO> pageDTO = new PageDTO<>(totalCount,articleVos);
        return pageDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ArticleVO read(Integer id,Integer uid) {
        Integer viewCount;
        String viewCountKey = "view_count:"+id;
        String viewCountCacheValue = stringRedisTemplate.opsForValue().get(viewCountKey);
        if(viewCountCacheValue!=null){
            viewCount = JSON.parseObject(viewCountCacheValue, Integer.class);
        }else {
            viewCount= articleDao.getViewCount(id);
            stringRedisTemplate.opsForValue().set(viewCountKey,JSONObject.toJSONString(viewCount));
        }
        Article article;
        if(viewCount>=HIT_ARTICLE_VIEW_COUNT){
            String articleKey = "article:" + id;
            String articleCacheValue = stringRedisTemplate.opsForValue().get(articleKey);
            if (articleCacheValue != null) {
                article = JSON.parseObject(articleCacheValue, Article.class);
                article.setViewCount(viewCount);
            } else {
                article = articleDao.read(id);
                stringRedisTemplate.opsForValue().set(articleKey, JSONObject.toJSONString(article));
                article.setViewCount(viewCount);
            }
        }else {
            article = articleDao.read(id);
            article.setViewCount(viewCount);
        }

        Boolean isLiked;
        if(uid==null){
            isLiked=false;
        }else if(likeDao.checkLike(id, 1, uid)>0){
            isLiked=true;
        }else {
            isLiked=false;
        }

        return new ArticleVO(
                article.getId(),
                article.getTitle(),
                article.getContent(),
                userDao.getById(article.getAuthorId()).getName(),
                userDao.getById(article.getAuthorId()).getId(),
                article.getCreateTime(),
                article.getViewCount(),
                article.getLikeCount(),
                article.getCommentCount(),
                isLiked);
    }

    @Override
    public void addViewCount(Integer id) {
        String viewCountKey = "view_count:"+id;
        String viewCountCacheValue = stringRedisTemplate.opsForValue().get(viewCountKey);
        articleDao.addViewCount(id);
        if(viewCountCacheValue!=null){
            stringRedisTemplate.boundValueOps(viewCountKey).increment(1);
        }else {
            Integer viewCount= articleDao.getViewCount(id);
            stringRedisTemplate.opsForValue().set(viewCountKey,JSONObject.toJSONString(viewCount));
        }
    }

    @Override
    public void addArticle(ArticleDTO articleDTO) {
        Audit audit = new Audit(null,
                articleDTO.getTitle(),
                articleDTO.getContent(),
                1,
                articleDTO.getAuthorId(),
                0, null, null, null,
                LocalDateTime.now(),
                null);
        adminDao.addAudit(audit);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteArticle(Integer id) {
        String articleKey = "article:"+id;
        String articleCacheValue = stringRedisTemplate.opsForValue().get(articleKey);
        if(articleCacheValue!=null){
            stringRedisTemplate.delete(articleKey);
        }
        articleDao.deleteArticle(id);
        String commentKey = "comment:1:"+id;
        String commentCacheValue = stringRedisTemplate.opsForValue().get(commentKey);
        if(commentCacheValue!=null){
            stringRedisTemplate.delete(commentKey);
        }
        commentDao.deleteCommentWhenDeleteItem(id,1);
    }
}
